/*
 * init.c
 * This file is part of COOG
 *
 * Copyright (C) 2012 - Luke Westby & Jon Gautsch
 *
 * lab10 is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * lab10 is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with lab10. If not, see <http://www.gnu.org/licenses/>.
 */

#include "synth.h"

/* -------------------------------------------------------------------------- *
 * init_soundcard()
 * prepare the soundcard for the type of audio it will be processesing
 * our synthesiser is mono (1 channel, no left and right) at a rate of
 * SAMPLERATE (in synth.h) and in 32 bit little-endian floats between -1 and 1
 * returns a pointer to the context structure for writing to the soundcard
 * -------------------------------------------------------------------------- */

pa_simple *init_soundcard() {

	int error;
	static const pa_sample_spec ss = {
        .format = PA_SAMPLE_FLOAT32LE,
        .rate = SAMPLERATE,
        .channels = 1
    };
    
    pa_simple *s = pa_simple_new(NULL,			// default audio server
    				  "Jon and Luke's Synth",	// application name
    				  PA_STREAM_PLAYBACK,		// playback stream
    				  NULL,						// default device found by server
    				  "playback",				// description of service
    				  &ss,						// format context
    				  NULL,						// default channel map
    				  NULL,						// default buffering attributes
    				  &error);
    
    return s;
}

/* -------------------------------------------------------------------------- *
 * init_sine(), init_square(), init_saw()
 * initialize each wavetable on the pointers provided in arguments
 * -------------------------------------------------------------------------- */

int init_sine(float *sine) {
	
	int i;
	
	// NULL
	if(!sine) return SYNTH_MEM_ERROR;
	
	// loop through each sample and place functional output on val to produce
	// a snapshot of the waveform which can be looped by a phase accumulator
	for(i = 0; i < WAVESIZE; i++) {
		sine[i] = (float)(sin((double)i/WAVESIZE*2*M_PI));
	}
	
	return SYNTH_SUCCESS;
}
/* -------------------------------------------------------------------------- */

int init_square(float *square) {
	
	int i;
	
	if(!square) return SYNTH_MEM_ERROR;
	
	for(i = 0; i < WAVESIZE; i++) {
		if(i < WAVESIZE/2) square[i] = 1.0;
		else square[i] = -1.0;
	}
	
	return SYNTH_SUCCESS;
}

/* -------------------------------------------------------------------------- */

int init_sawtooth(float *sawtooth) {
	
	int i;
	
	if(!sawtooth) return SYNTH_MEM_ERROR;
	
	for(i = 0; i < WAVESIZE; i++) {
		sawtooth[i] = (float)((WAVESIZE-i)/(float)WAVESIZE)*2.0 - 1.0;
	}
	
	return SYNTH_SUCCESS;
}

/* -------------------------------------------------------------------------- *
 * init_wavetables()
 * blanket function for init_* functions. makes life a little easier
 * -------------------------------------------------------------------------- */

int init_wavetables(float *saw, float *sqr, float *sine) {
	
	int r;
	
	r = init_sawtooth(saw);
	if(r != SYNTH_SUCCESS) return r;
	
	r = init_square(sqr);
	if(r != SYNTH_SUCCESS) return r;

	r = init_sine(sine);
	if(r != SYNTH_SUCCESS) return r;
	
	return SYNTH_SUCCESS;
}

/* -------------------------------------------------------------------------- *
 * init_freqtable()
 * generate a lookup table to convert semitone numbers to actual frequencies
 * frequencies produced are perfect and not eulerian. the algorithm used is
 * based on that used in "vstxsynthproc.cpp" from the VST2.4 SDK from Steinberg.
 * -------------------------------------------------------------------------- */

int init_freqtable(double *freqs) {
	
	int i;
	double k, c;
	
	if(!freqs) return SYNTH_MEM_ERROR;
	
	k  = 1.059463094359;	// 12th root of 2, ratio of two adjacent semitones
	c  = 130.81;			// C3, so says the internet
	
	// loop and multiply
	for (i = 0; i < NNOTES; i++) {
		freqs[i] = c;
		c *= k;
	}

	return SYNTH_SUCCESS;
}
